#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <wait.h>
#include <netdb.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "open.h"

#define MAXLINE     1024

void echo(int connfd)
{
    ssize_t n;
    char buf[MAXLINE];

    while((n = read(connfd, buf, MAXLINE)) > 0)
    {
        printf("server received %d bytes\n", n);
        write(connfd, buf, n);
    }
    if (n < 0)
        perror("read error");
}

void sigchld_handler(int sig)
{
    while (waitpid(-1, 0, WNOHANG) > 0);
}

int main(int argc, char const* argv[])
{
    int listenfd, connfd, port, clientlen;
    struct sockaddr_in clientaddr;
    struct hostent *hp;
    char *haddrp;
    fd_set read_set, ready_set;
    char buf[MAXLINE];

    if (argc != 2)
    {
        printf("usage: %s <port>\n", argv[0]);
        exit(0);
    }

    port = atoi(argv[1]);

    listenfd = open_listenfd(port);
    if (listenfd < 0)
    {
        perror("open listenfd error");
        exit(0);
    }

    FD_ZERO(&read_set);
    FD_SET(STDIN_FILENO, &read_set);
    FD_SET(listenfd, &read_set);

    while(1)
    {
        ready_set = read_set;
        select(listenfd+1, &ready_set, NULL, NULL, NULL);

        /* read command line from stdin */
        if (FD_ISSET(STDIN_FILENO, &ready_set))
        {
            fgets(buf, MAXLINE, stdin);
            if (feof(stdin))
                exit(0);
            printf("%s", buf); 
        }

        /* echo client input */
        if (FD_ISSET(listenfd, &ready_set))
        {
            clientlen = sizeof(clientaddr);
            connfd = accept(listenfd, (struct sockaddr *)&clientaddr, 
                &clientlen);
            if (connfd < 0)
            {
                printf("accept error\n");
                exit(0);
            }

            if (fork() == 0)
            {
                close(listenfd);
                /* determine the domain name and IP address of the client */
                hp = gethostbyaddr((const char *)&clientaddr.sin_addr.
                    s_addr,
                    sizeof(struct in_addr), AF_INET);
                haddrp = inet_ntoa(clientaddr.sin_addr);
                printf("server connected to %s (%s)\n", hp->h_name, haddrp);
                echo(connfd);
                close(connfd);
                exit(0);
            }
            
            /* parent close connected socket */
            close(connfd);
        }
    }

    return 0;
}
